# -*- coding: utf-8 -*-
import json
import os
import sys
import time
import pandas as pd
import qtawesome as qta
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QSize, QDateTime, QDate, QTime
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QPainter
from PyQt5.QtWidgets import QVBoxLayout, QLabel, QMainWindow, QGraphicsScene, QHBoxLayout, QPushButton, QWidget, \
    QHeaderView, QStyledItemDelegate, QItemDelegate, QAbstractItemView, QApplication, QStackedWidget, QTableWidget, \
    QTableWidgetItem
from PyQt5.QtChart import QChart, QChartView, QLineSeries, QDateTimeAxis, QSplineSeries, QValueAxis

from base.window.base_window import BaseWidget
from buss_api.chart_manage import ChartManage
from buss_api.config_tools import ConfigTools
from buss_api.db_manage import DbManage
from buss_api.service_manage import ServiceManage
from global_data.constant_data import ConstantData
from global_data.glabal_data import GlobalData
from mq.zmq.zmq_x_proxy import ZmqXProxy
from pyqt_api.send_config_edit_api import SendConfigEditApi
from pyqt_api.sys_config_edit_api import SysConfigEdit
from pyqt_api.sys_tray import SystemTrayApp
from pyqt_api.test.win_test import WindowTest
from pyqt_api.tools.dete_time_edit import DateTimeEdit
from pyqt_api.zmq.zmq_pub_form import ZmqPubForm
from pyqt_api.zmq.zmq_sub_form import ZmqSubForm
from utils.dialog_utils import DialogUtils
from utils.file_utils import FileUtils
from utils.icloudp_log import IcloudpLog
from utils.json_utils import JsonUtils
from utils.send_mail import SendMail
from utils.str_utils import StrUtils
from utils.sys_tools import SystemTools
from utils.time_utils import TimeUtils
from windows.smart_getway import Ui_MainWindow

"""
处理主页面显示
"""


class SmartGatewayApi(object):
    def __init__(self, app, form):
        self.log = IcloudpLog.get_logger_sys()
        # 系统配置编辑页面
        self.page_status = {
            "sys_config": True,
            "send_config": True,
            "monitor": True,
            "zmq": True,
            "common": True,
            "service": True,
            "db_manage": True,
            "chart": True
        }
        # 状态栏变量
        self.lab_status_bar_right = None
        self.lab_status_bar_left = None
        # top按钮变量
        self.top_btns = None
        # zmq页面变量
        self.zmq_server = None
        # 系统配置页面变量
        self.sys_config_dialog_win = None
        self.sys_config_edit_win = None
        self.send_config_form = None
        self.sys_config_json = None
        self.monitor_procs = []
        self.monitor_services = []
        self.monitor_tv_proc_model = None
        self.monitor_tv_service_model = None
        # zmq区域
        self.zmq_proxy = None
        self.win_pubs = {}
        self.win_subs = {}
        # chart区域变量
        self.chart_files_list = []
        self.chart_point_data = []
        self.chart_layers = []

        # 公共变量
        self.ui = Ui_MainWindow()
        self.win = form
        self.app = app
        self.win.setWindowIcon(qta.icon(GlobalData.SYS_IMG))
        self.curr_page = 0
        self.tray = SystemTrayApp(self.app, self.win)
        self.init()
        # 绑定事件
        self.bind_events()

    def init(self):
        """
        主页面初始化
        :return:
        """
        self.ui.setupUi(self.win)
        # 设置名称
        self.ui.lab_title.setText(GlobalData.SYS_NAME)
        # 初始化变量
        self.top_btns = [self.ui.btn_sys_config, self.ui.btn_send_config, self.ui.btn_monitor, self.ui.btn_zmq,
                         self.ui.btn_common, self.ui.btn_service, self.ui.btn_db_manage, self.ui.btn_chart]

        # 设置样式
        self.set_style()

        # 默认先隐藏
        for index, btn in enumerate(self.top_btns):
            # name = btn.objectName()
            btn.hide()

        # 根据配置显示
        for index, name in enumerate(GlobalData.SYS_SHOW):
            button = self.get_btn_by_name('btn_' + name)
            if button:
                button.show()

    def bind_events(self):
        # 状态栏事件
        # 添加第一个区域
        self.lab_status_bar_left = QLabel("左侧区域")
        self.ui.statusbar.addWidget(self.lab_status_bar_left)

        # 添加第二个区域
        self.lab_status_bar_right = QLabel("右侧区域")
        self.ui.statusbar.addPermanentWidget(self.lab_status_bar_right)
        timer = QtCore.QTimer(self.win)  # 创建一个QTimer计时器对象
        timer.timeout.connect(self.show_time_statusbar)  # 发射timeout信号，与自定义槽函数关联
        timer.start()  #

        # 顶部按钮
        self.ui.btn_sys_config.clicked.connect(lambda: self.switch_page("sys_config"))
        self.ui.btn_send_config.clicked.connect(lambda: self.switch_page("send_config"))
        self.ui.btn_monitor.clicked.connect(lambda: self.switch_page("monitor"))
        self.ui.btn_zmq.clicked.connect(lambda: self.switch_page("zmq"))
        self.ui.btn_common.clicked.connect(lambda: self.switch_page("common"))
        self.ui.btn_service.clicked.connect(lambda: self.switch_page("service"))
        self.ui.btn_db_manage.clicked.connect(lambda: self.switch_page("db_manage"))
        self.ui.btn_chart.clicked.connect(lambda: self.switch_page("chart"))
        # self.ui.btn_update_sys.clicked.connect(lambda: self.switch_page("update_sys"))
        self.ui.btn_quit.clicked.connect(lambda: self.exit_sys())

        # 系统配置页面  发送配置
        self.ui.btn_sys_load_def.clicked.connect(lambda: self.load_def_config(0))
        self.ui.btn_send_load_def.clicked.connect(lambda: self.load_def_config(1))

        self.ui.btn_sys_load.clicked.connect(lambda: self.load_user_config(0))
        self.ui.btn_send_load.clicked.connect(lambda: self.load_user_config(1))

        self.ui.btn_sys_check.clicked.connect(lambda: self.check_json(0))
        self.ui.btn_send_check.clicked.connect(lambda: self.check_json(1))

        self.ui.btn_sys_export.clicked.connect(lambda: self.export_json(0))
        self.ui.btn_send_export.clicked.connect(lambda: self.export_json(1))

        self.ui.btn_sys_edit.clicked.connect(lambda: self.open_sys_config_form())
        self.ui.btn_send_edit.clicked.connect(lambda: self.open_send_config_form())

        # 监控页面事件
        self.ui.btn_monitor_process_check.clicked.connect(self.get_proc_status)
        self.ui.btn_monitor_process_kill.clicked.connect(self.kill_proc)
        self.ui.btn_monitor_process_kill_force.clicked.connect(self.kill_proc, True)
        self.ui.btn_monitor_service_check.clicked.connect(self.check_service)
        self.ui.btn_monitor_service_start.clicked.connect(self.start_service)
        self.ui.btn_monitor_service_stop.clicked.connect(self.stop_service)
        self.ui.btn_monitor_proc_load.clicked.connect(self.reload_processs)
        self.ui.btn_monitor_service_load.clicked.connect(self.reload_services)

        # zmq 相关
        self.ui.btn_zmq_create.clicked.connect(self.zmq_start_proxy)
        self.ui.btn_zmq_new_pub.clicked.connect(self.zmq_new_pub)
        self.ui.btn_zmq_new_sub.clicked.connect(self.zmq_new_sub)

        # 通用工具
        # 邮件
        self.ui.btn_common_mail_attach.clicked.connect(self.select_mail_attach)
        self.ui.btn_common_mail_send.clicked.connect(self.send_mails)

        # 服务管理
        self.ui.btn_service_gateway_check.clicked.connect(lambda: self.service_check("gateway"))
        self.ui.btn_service_gateway_stop.clicked.connect(lambda: self.service_stop("gateway"))
        self.ui.btn_service_gateway_back.clicked.connect(lambda: self.service_backup("gateway"))
        self.ui.btn_service_gateway_update.clicked.connect(lambda: self.service_update_file("gateway"))
        self.ui.btn_service_gateway_start.clicked.connect(lambda: self.service_start("gateway"))
        self.ui.btn_service_web_check.clicked.connect(lambda: self.service_check("web"))
        self.ui.btn_service_web_stop.clicked.connect(lambda: self.service_stop("web"))
        self.ui.btn_service_web_back.clicked.connect(lambda: self.service_backup("web"))
        self.ui.btn_service_web_update.clicked.connect(lambda: self.service_update_file("web"))
        self.ui.btn_service_web_start.clicked.connect(lambda: self.service_start("web"))

        self.ui.btn_service_gateway_reset.clicked.connect(lambda: self.service_reset("gateway"))
        self.ui.btn_service_web_reset.clicked.connect(lambda: self.service_reset("web"))
        self.ui.btn_service_web_clear_cache.clicked.connect(lambda: self.service_restart_cs())
        self.ui.btn_service_web_clear_cache.hide()

        self.ui.btn_service_gateway_program_path.clicked.connect(lambda: self.service_select_dir(1))
        self.ui.btn_service_gateway_back_path.clicked.connect(lambda: self.service_select_dir(2))
        self.ui.btn_service_gateway_file_path.clicked.connect(lambda: self.service_select_dir(3))
        self.ui.btn_service_web_program_path.clicked.connect(lambda: self.service_select_dir(6))
        self.ui.btn_service_web_back_path.clicked.connect(lambda: self.service_select_dir(7))
        self.ui.btn_service_web_file_path.clicked.connect(lambda: self.service_select_dir(8))

        self.ui.btn_service_gateway_start_all.clicked.connect(lambda: self.service_start_all("gateway"))
        self.ui.btn_service_web_start_all.clicked.connect(lambda: self.service_start_all("web"))

        # dbmanage 管理页面
        self.ui.btn_db_src_link.clicked.connect(lambda: self.db_link_test("src"))
        self.ui.btn_db_target_link.clicked.connect(lambda: self.db_link_test("target"))
        self.ui.btn_db_table.clicked.connect(lambda: self.check_tabs())
        self.ui.btn_db_proc.clicked.connect(lambda: self.check_proc())
        self.ui.btn_db_clear.clicked.connect(lambda: self.db_clear_table())
        self.ui.btn_db_other.clicked.connect(lambda: self.db_other())

        # chart页面
        # self.ui.btn_chart_files.clicked.connect(lambda: self.chart_files())
        self.ui.btn_chart_csv_path.clicked.connect(lambda: self.chart_csv_path())
        # self.ui.btn_chart_load_data.clicked.connect(lambda: self.chart_load_data())
        self.ui.btn_chart_query.clicked.connect(lambda: self.chart_query())
        # self.ui.btn_chart_chart.clicked.connect(lambda: self.chart_show())
        self.ui.lw_chart_files.itemClicked.connect(self.chart_file_event)
        self.ui.btn_chart_flush_layer.clicked.connect(self.chart_flush_layer)
        self.ui.btn_chart_query_files.clicked.connect(self.chart_query_files)
        self.ui.btn_chart_date_select.clicked.connect(lambda: self.chart_datetime_select("date"))
        self.ui.btn_chart_time_select.clicked.connect(lambda: self.chart_datetime_select("time_range"))

        # 更新还原页面

        # 初始化方法
        self.switch_page(GlobalData.SYS_SHOW[0])

    # 主页配置相关 =================================
    def exit_sys(self):
        """
        安全退出
        :return:
        """
        try:
            self.tray.quit_app()
        except Exception as e:
            IcloudpLog.error(f"退出程序错误: {e}")
            DialogUtils.alert(f"退出程序错误: {e}")

    def set_style(self):
        # 加载系统图标
        pixmap = qta.icon(GlobalData.SYS_IMG, active="mdi6.cloud-cog", color="red", color_active="blue").pixmap(
            QSize(40, 40))
        scene = QGraphicsScene()
        scene.addPixmap(pixmap)
        self.ui.img_sys.setScene(scene)  # 隐藏水平滚动条
        self.ui.img_sys.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # 隐藏垂直滚动条
        self.ui.img_sys.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.ui.img_sys.setStyleSheet('border: 0px; color: red; background-color: #f0f0f0;')  # 设置边框宽度为0

        # 设置按钮的样式表，使得图标和文本垂直居中，并且文本换行
        self.set_button_icon_center(self.ui.btn_sys_config, "系统配置", qta.icon('fa5b.hive', color="#fff"))
        self.set_button_icon_center(self.ui.btn_send_config, "发送配置", qta.icon('fa5b.instalod', color="#fff"))
        self.set_button_icon_center(self.ui.btn_monitor, "网关监控", qta.icon('fa5b.sith', color="#fff"))
        self.set_button_icon_center(self.ui.btn_zmq, "消息管理", qta.icon('fa5b.studiovinari', color="#fff"))
        self.set_button_icon_center(self.ui.btn_common, "通用工具", qta.icon('fa.cogs', color="#fff"))
        self.set_button_icon_center(self.ui.btn_service, "服务管理", qta.icon('mdi6.bowl-mix', color="#fff"))
        self.set_button_icon_center(self.ui.btn_db_manage, "数据库", qta.icon('fa5b.stack-exchange', color="#fff"))
        self.set_button_icon_center(self.ui.btn_chart, "图表管理", qta.icon('fa5b.uncharted', color="#fff"))
        # self.set_button_icon_center(self.ui.btn_update_sys, "更新还原", qta.icon('fa5b.uncharted', color="#fff"))
        self.set_button_icon_center(self.ui.btn_quit, "安全退出", qta.icon('mdi.exit-to-app', color="#fff"))
        self.win.setStyleSheet("""
                            .QWidget {border-width: 0px; border-style: none;}
                            .QStackedWidget {border-width: 0px; border-style: none;}
                            QFrame {border-width: 0; border-style: none;}
                            QGroupBox::title {line-height: 30px; margin-bottom: -10px; }
                            QLabel {font: 16px 宋体 ; color: #fff;}
                            QDateEdit {font: 14px 宋体 ; color: #fff;}
                            QTimeEdit {font: 14px 宋体 ; color: #fff;}
                            QDateTimeEdit {font: 14px 宋体 ; color: #fff;}
                            QLineEdit {font: 16px 宋体 ; color: #fff;}
                            QPlainTextEdit {font: 16px 宋体 ; color: #fff; border-width: 1px; border-style: solid;}
                            QPushButton {font: 16px 宋体 ; color: #fff; height:25px; width:120px;}
                            QTextEdit {font: 16px 宋体 ; color: #fff; border-width: 1px; border-style: solid;}
                            QTextBrowser {font: 16px 宋体 ; color: #fff; }
                            QComboBox {font: 16px 宋体 ; color: #fff;}
                            #fm_top {border-bottom:3px solid #000;}
                            #fm_top QLabel {font: bold 34px "微软雅黑","Arial";}
                            #fr_chart_left {border-width: 2px; border-style: solid; frameShape:box;}
                            #fr_chart_right {border-width: 2px; border-style: solid; frameShape:box;}
                        """)
        self.update_styte()

    def update_styte(self):
        self.ui.wg_top_btns.setStyleSheet('''
                                QPushButton{
                                    font:bold;
                                    color:white;
                                    border-radius:0px;
                                    margin-right:3px;
                                }
                                QPushButton>QLabel{
                                    background: transparent
                                }
                               .QPushButton{
                                    background-color: #19232d;
                                }
                                .QPushButton[ischeck=selected]{
                                    background-color: #1fa977;
                                }
                                .QPushButton:hover{
                                    background-color: #1fa977;
                                }
                            ''')

    def set_button_color(self, name):
        """
        点击时设置按钮颜色
        :return:
        """
        name = "btn_" + name
        # btn = self.get_btn_by_name(name)
        for i, element in enumerate(self.top_btns):
            element.setProperty("ischeck", "none")
            if name == element.objectName():
                element.setProperty("ischeck", "selected")
                # element.setStyleSheet(f".QPushButton {{background-color: #1fa977}}")
            else:
                element.setProperty("ischeck", "none")
                # element.setStyleSheet(f"QPushButton {{background-color: #19232d}}")
        self.update_styte()

    def switch_page(self, name=""):
        """
        切换page
        :param name:
        :return:
        """
        # self.ui.main_widget.setCurrentIndex(index)
        self.ui.main_widget.setCurrentWidget(self.get_btn_by_name("page_" + name, obj=QWidget))
        # index = self.ui.main_widget.currentIndex()
        # self.curr_page = index
        self.set_button_color(name)
        self.init_page(name)

    def init_page(self, name):
        """
        根据情况初始化页面  避免重复初始化
        :param name:
        :return:
        """
        if not self.page_status[name]:
            return

        if name == 'monitor':
            self.ui.txt_monitor_process_name.setText("monSmartGateway.exe")
            self.ui.txt_monitor_service_name.setText("monSmartGateway")
            self.get_services_procs("all")
            self.init_tv_monitor_proc()
            self.set_tv_monitor_proc_data()
            self.init_tv_monitor_service()
            self.set_tv_monitor_service_data()
        elif name == "zmq":
            # 初始化zmq数据
            self.ui.txt_zmq_pub_host.setText(GlobalData.ZMQ_XPUB_IP)
            self.ui.txt_zmq_pub_port.setText(GlobalData.ZMQ_XPUB_PORT)
            self.ui.txt_zmq_sub_host.setText(GlobalData.ZMQ_XSUB_IP)
            self.ui.txt_zmq_sub_port.setText(GlobalData.ZMQ_XSUB_PORT)
        elif name == "service":
            self.ui.txt_service_gateway_back_path.setText(GlobalData.SERVICE_BACKUP_PATH)
            self.ui.txt_service_gateway_file_path.setText(GlobalData.SERVICE_FILE_PATH)
            self.ui.txt_service_gateway_program_path.setText(GlobalData.SERVICE_PROGRAM_PATH)
            self.ui.txt_service_web_back_path.setText(GlobalData.SERVICE_BACKUP_PATH)
            self.ui.txt_service_web_file_path.setText(GlobalData.SERVICE_FILE_PATH)
            self.ui.txt_service_web_program_path.setText(GlobalData.SERVICE_PROGRAM_PATH)
        elif name == 'db_manage':
            self.ui.txt_db_src_ip.setText(GlobalData.DB_SOURCE_HOST)
            self.ui.txt_db_src_port.setText(GlobalData.DB_SOURCE_PORT)
            self.ui.txt_db_src_name.setText(GlobalData.DB_SOURCE_USER)
            self.ui.txt_db_src_pwd.setText(GlobalData.DB_SOURCE_PWD)
            self.ui.txt_db_src_db.setText(GlobalData.DB_SOURCE_DB)
            self.ui.txt_db_target_ip.setText(GlobalData.DB_TARGET_HOST)
            self.ui.txt_db_target_port.setText(GlobalData.DB_TARGET_PORT)
            self.ui.txt_db_target_name.setText(GlobalData.DB_TARGET_USER)
            self.ui.txt_db_target_pwd.setText(GlobalData.DB_TARGET_PWD)
            self.ui.txt_db_target_db.setText(GlobalData.DB_TARGET_DB)

            # print(f"src   ip={GlobalData.DB_SOURCE_HOST}, port={GlobalData.DB_SOURCE_PORT}, user= {GlobalData.DB_SOURCE_USER}, pwd={GlobalData.DB_SOURCE_PWD}, db={GlobalData.DB_SOURCE_DB}")
            # print(f"tar   ip={GlobalData.DB_TARGET_HOST}, port={GlobalData.DB_TARGET_PORT}, user= {GlobalData.DB_TARGET_USER}, pwd={GlobalData.DB_TARGET_PWD}, db={GlobalData.DB_TARGET_DB}")
        elif name == 'chart':
            self.ui.tw_chart_data.setColumnCount(2)
            self.ui.tw_chart_data.setRowCount(0)
            self.ui.tw_chart_data.setShowGrid(True)
            self.ui.tw_chart_data.setHorizontalHeaderLabels(('货位', '温度'))
            self.ui.tw_chart_data.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
            self.ui.tw_chart_data.setColumnWidth(0, 200)
            self.ui.tw_chart_data.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置选择整行
            self.ui.tw_chart_data.cellClicked.connect(self.chart_tw_rowclick_event)
            self.ui.date_chart_curr.setDate(QDate.currentDate())
            self.ui.txt_chart_csv_path.setText(GlobalData.CHART_CSV_PATH)
            self.chart_flush_layer()
            self.ui.time_chart_begin.setTime(QTime.currentTime().addSecs(-1*10*60))
            self.ui.time_chart_end.setTime(QTime.currentTime())

        self.page_status[name] = False

    def set_button_icon_center(self, button, label, icon):
        button.setText("")
        # 创建一个垂直布局，将图标和文字放入其中
        button_layout = QVBoxLayout(button)
        button_layout.setContentsMargins(9, 9, 9, 9)  # 设置布局的外边距为9
        button_layout.setSpacing(9)  # 设置布局的控件间距为0

        icon_label = QLabel()  # 创建一个标签用于显示图标
        icon_label.setPixmap(icon.pixmap(QSize(30, 30)))
        icon_label.setAlignment(Qt.AlignCenter)  # 设置图标居中对齐

        text_label = QLabel(label)  # 创建一个标签用于显示文字
        text_label.setAlignment(Qt.AlignCenter)  # 设置文字居中对齐
        text_label.setStyleSheet("font-family:微软雅黑; font-size: 18px; font-weight: 700")

        button_layout.addWidget(icon_label)  # 将图标标签添加到按钮的垂直布局中
        button_layout.addWidget(text_label)  # 将文字标签添加到按钮的垂直布局中

    def show_time_statusbar(self):
        """
        状态栏显示时间
        :return:
        """
        try:
            datetime = TimeUtils.get_current_time()  # 获取当前日期时间
            # self.ui.statusbar.showMessage('当前日期时间：' + datetime, 0)  # 在状态栏中显示日期时间
            # self.ui.statusbar.showMessage('当前日期：' + datetime, 1)  # 在状态栏中显示日期时间
            # 或者这句MainWindow.statusBar().showMessage('当前日期时间：' + text, 0)  # 在状态栏中显示日期时间
            self.lab_status_bar_left.setText(f"icloudp {ConstantData.VERSION}")
            self.lab_status_bar_right.setText(f"当前时间： {datetime}")
        except Exception as e:
            IcloudpLog.error(f"更新状态栏时间错误: {e}")
            DialogUtils.alert(f"更新状态栏时间错误: {e}")
            return

    # 系统配置相关 ============================================
    def load_def_config(self, index):
        """加载json文件"""
        if index == 0:
            file_path = "outfile/bigrelay/config/sysConfig.txt"
        else:
            file_path = "outfile/bigrelay/config/sendConfig.txt"
        try:
            data = JsonUtils.json_path_str(file_path)
            jsonstr = JsonUtils.format_json(data)
        except Exception as e:
            IcloudpLog.error(f"加载文件失败: {e}")
            DialogUtils.alert(f"加载文件失败: {e}")
            return
        if index == 0:
            self.ui.txt_sys_config.setText(jsonstr)
        else:
            self.ui.txt_send_config.setText(jsonstr)

    def load_user_config(self, index):
        """
        载入用户配置
        :param index:
        :return:
        """
        file_path, file_type = DialogUtils.get_file(ext="json文本(*.txt)")
        if file_path:
            try:
                data = JsonUtils.json_path_str(file_path)
                json_str = JsonUtils.format_json(data)
            except Exception as e:
                IcloudpLog.error(f"读取文件错误: {e}")
                DialogUtils.alert(f"读取文件错误: {e}")
                return

            if index == 0:
                self.ui.txt_sys_config.setText(json_str)
            else:
                self.ui.txt_send_config.setText(json_str)

    def set_page_txt(self, data, index):
        """
        填充文本框
        :param data:
        :param index:
        :return:
        """
        try:
            json_str = JsonUtils.format_json_str(data)
        except Exception as e:
            IcloudpLog.error(f"读取文件错误: {e}")
            DialogUtils.alert(f"读取文件错误: {e}")
            return
        if index == 0:
            self.ui.txt_sys_config.setText(json_str)
        else:
            self.ui.txt_send_config.setText(json_str)

    def check_json(self, index):
        """
        校验用户输入字符
        :param index:
        :return:
        """
        if index == 0:
            data = self.ui.txt_sys_config.toPlainText()
        else:
            data = self.ui.txt_send_config.toPlainText()
        if data is not None and data != '':
            try:
                json.loads(data)
                DialogUtils.msg("校验成功，可以放心导出！")
            except Exception as e:
                DialogUtils.alert(f"数据格式有误，请检查！{e}")
                IcloudpLog.error(f"数据格式有误：{e}")
                return

    def export_json(self, index):
        """
        根据文本内容导出
        :param index:
        :return:
        """
        if index == 0:
            data = self.ui.txt_sys_config.toPlainText()
            filename = "sysConfig.txt"
        else:
            data = self.ui.txt_send_config.toPlainText()
            filename = "sendConfig.txt"
        if data is not None and data != '':
            print(data)
            try:
                # 打开文件进行写入
                path = DialogUtils.get_dir()
                print(path)
                if path:
                    JsonUtils.write_str_json(data, FileUtils.join_path(path, filename), True)
                    DialogUtils.msg("导出成功！")
            except Exception as e:
                DialogUtils.alert("导出文件错误，请检查！")
                IcloudpLog.error(f"导出文件错误：{e}")
                return
        else:
            DialogUtils.warn("没有任何内容导出！！！")

    def get_data(self, index):
        """
        获取页面数据
        :return:
        """
        if index == 0:
            data = self.ui.txt_sys_config.toPlainText()
        else:
            data = self.ui.txt_send_config.toPlainText()
        if data is not None and data != '':
            try:
                return JsonUtils.json_to_obj(data)
            except Exception as e:
                IcloudpLog.error(f"格式化数据错误: {e}")
                DialogUtils.alert(f"格式化数据错误: {e}")
                return
        else:
            return None

    def open_sys_config_form(self):
        """
        打开sys编辑窗口
        两种方式打开窗口
        1、通过模态窗口处理
        2、窗口置顶
        :return:
        """
        # 创建对象
        self.sys_config_edit_win = SysConfigEdit(self.get_data(0), self)
        # self.sys_config_dialog_win = ModalMainWindow(self.sys_config_edit_win.win)
        self.sys_config_edit_win.show()

    def open_send_config_form(self):
        """
        打开发送配置窗口
        :return:
        """
        # 创建对象
        self.send_config_form = SendConfigEditApi(title="发送配置", ui_path="send_config_edit.ui", parent=self,
                                                  data=self.get_data(1))
        # self.send_config_edit_win = BaseWidget(self.get_data(1), self)
        # self.send_config_dialog_win = ModalMainWindow(self.send_config_edit_win.win)
        self.send_config_form.show()

    # 网关监控相关 ------------------------------------------------
    def get_proc_status(self):
        """
        获取进程状态及详情
        :return:
        """
        msg = ""
        try:
            proc_name = self.ui.txt_monitor_process_name.text()
            if proc_name:
                res = SystemTools.process_exists(proc_name)
                if res:
                    msg = msg + "当前进程已存在，详情情况如下：\n"
                    temp = SystemTools.get_proc_info_str(proc_name)
                    msg = msg + f"{temp}"
                    self.ui.tb_monitor_process_msg.append(msg)
                else:
                    self.ui.tb_monitor_process_msg.append("当前进程不存在")
            else:
                DialogUtils.warn("请输入进程名称")
        except Exception as e:
            IcloudpLog.error(f"获取进程状态失败: {e}")
            DialogUtils.alert(f"获取进程状态失败: {e}")

    def kill_proc(self, is_force=False):
        """
        结束进程
        :return:
        """
        try:
            proc_name = self.ui.txt_monitor_process_name.text()
            if proc_name:
                res = SystemTools.process_exists(proc_name)
                if res:
                    SystemTools.kill_proc(proc_name, is_force)
                    self.ui.tb_monitor_process_msg.append("已结束进程，请检查")
                    DialogUtils.warn("已结束进程，请检查")
                else:
                    self.ui.tb_monitor_process_msg.append("当前进程不存在")
                    DialogUtils.warn("当前进程不存在")
            else:
                DialogUtils.warn("请输入进程名称")
        except Exception as e:
            IcloudpLog.error(f"结束进程失败: {e}")
            DialogUtils.alert(f"结束进程失败: {e}")

    def check_service(self):
        """
        检查服务状态
        :return:
        """
        try:
            service_name = self.ui.txt_monitor_service_name.text()
            if service_name:
                res = SystemTools.get_service_status(service_name)
                if res == 1:
                    msg = f"当前服务{service_name}已停止"
                elif res == 4:
                    msg = f"当前服务{service_name}正在运行"
                else:
                    msg = f"当前服务{service_name}异常不存在"
                self.ui.tb_monitor_service_msg.append(msg)
            else:
                self.ui.tb_monitor_service_msg.append("请输入服务名称")
                DialogUtils.warn("请输入服务名称")
        except Exception as e:
            IcloudpLog.error(f"检查服务失败: {e}")
            self.ui.tb_monitor_service_msg.append(f"检查服务失败: {e}")

    def start_service(self):
        """
        启动服务
        :return:
        """
        service_name = self.ui.txt_monitor_service_name.text()
        if service_name:
            try:
                SystemTools.start_service(service_name)
                self.ui.tb_monitor_service_msg.append("服务已启动，请检查")
            except Exception as e:
                IcloudpLog.error(f"服务启动失败: {e}")
                DialogUtils.alert(f"服务启动失败: {e}")
        else:
            DialogUtils.warn("请输入服务名称")

    def stop_service(self):
        """
        停止服务
        :return:
        """
        service_name = self.ui.txt_monitor_service_name.text()
        if service_name:
            try:
                SystemTools.stop_service(service_name)
                self.ui.tb_monitor_service_msg.append("服务已停止，请检查")
            except Exception as e:
                IcloudpLog.error(f"服务停止失败: {e}")
                DialogUtils.alert(f"服务停止失败: {e}")
        else:
            DialogUtils.warn("请输入服务名称")

    # 进程列表相关操作
    def get_services_procs(self, info):
        """
        根据配置获取进程和服务的名称列表
        :param info:
        :return:
        """
        try:
            if info == "proc":
                self.monitor_procs = list(ConfigTools.get_value("monitor", "process").split(","))
            elif info == "service":
                self.monitor_services = list(ConfigTools.get_value("monitor", "service").split(","))
            else:
                self.monitor_procs = list(ConfigTools.get_value("monitor", "process").split(","))
                self.monitor_services = list(ConfigTools.get_value("monitor", "service").split(","))
        except Exception as e:
            IcloudpLog.error(f"获取监控配置失败: {e}")
            DialogUtils.alert(f"获取监控配置失败: {e}")

    def init_tv_monitor_proc(self):
        """
        创建模型并关联
        :return:
        """
        # 创建一个数据模型
        self.monitor_tv_proc_model = QStandardItemModel(0, 4)
        # 设置数据模型的表头标签
        self.monitor_tv_proc_model.setHorizontalHeaderLabels(["序号", "进程", "状态", "信息"])
        self.ui.tv_monitor_proc.setModel(self.monitor_tv_proc_model)
        self.ui.tv_monitor_proc.resizeColumnsToContents()  # 调整所有列的宽度以适应内容
        self.ui.tv_monitor_proc.resizeRowsToContents()  # 调整所有行的高度以适应内容
        self.ui.tv_monitor_proc.showGrid()  # 显示网格线
        self.ui.tv_monitor_proc.setSortingEnabled(True)  # 排序
        self.ui.tv_monitor_proc.horizontalHeader().setStretchLastSection(True)
        # self.ui.tv_monitor_procsetItemDelegate(CustomDelegate()) # 委托
        self.ui.tv_monitor_proc.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 表格填满窗口
        self.ui.tv_monitor_proc.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置选择行为为选择整行
        self.ui.tv_monitor_proc.setSelectionMode(QAbstractItemView.SingleSelection)  # 设置选择模式为单选
        self.ui.tv_monitor_proc.selectionModel().selectionChanged.connect(
            self.handle_proc_selection_changed)  # 连接选择变化信号与槽函数

    def set_tv_monitor_proc_data(self):
        """
        填充数据
        :return:
        """
        try:
            procs_info = SystemTools.get_procs_info_str(self.monitor_procs)
            for index, proc in enumerate(self.monitor_procs):
                proc_lower = proc.strip().lower()
                # self.monitor_tv_proc_model.appendRow(
                #     [
                #         QStandardItem(index),
                #         QStandardItem(proc.strip()),
                #         QStandardItem("未知"),
                #         QStandardItem(proc_info),
                #         self.__add_monitor_tv_proc_btn()
                #     ]
                # )
                self.monitor_tv_proc_model.setItem(index, 0, QStandardItem(str(index + 1)))
                self.monitor_tv_proc_model.setItem(index, 1, QStandardItem(proc.strip()))
                self.monitor_tv_proc_model.setItem(index, 2, QStandardItem("未知"))
                self.monitor_tv_proc_model.setItem(index, 3, QStandardItem(
                    (procs_info[proc_lower] if procs_info.get(proc_lower) else "进程不存在")))
                # self.ui.tv_monitor_proc.setW(index-1, 5, self.__add_monitor_tv_proc_btn())
            self.ui.tv_monitor_proc.resizeColumnsToContents()  # 调整所有列的宽度以适应内容
            # self.ui.tv_monitor_proc.setItemDelegateForColumn(4, TableViewButtonDelegate(self.ui.tv_monitor_proc))
        except Exception as e:
            IcloudpLog.error(f"tableview填充数据失败: {e}")
            DialogUtils.alert(f"tableview填充数据失败: {e}")

    def reload_processs(self):
        """
        刷新服务
        :return:
        """
        self.init_tv_monitor_proc()
        self.set_tv_monitor_proc_data()

    def handle_proc_selection_changed(self, selected):
        """
        行选中事件
        :param selected:
        :return:
        """
        if selected.indexes():
            row = selected.indexes()[0].row()  # 获取选中行的索引
            # values = [self.monitor_tv_proc_model.item(row, column).text() for column in range(self.monitor_tv_proc_model.columnCount())]  # 获取选中行的值
            # print("选中行的值：", values)
            self.ui.txt_monitor_process_name.setText(self.monitor_tv_proc_model.item(row, 1).text())
            self.ui.tb_monitor_process_msg.append(self.monitor_tv_proc_model.item(row,
                                                                                  3).text() + "\n-----------------------------------------------------------")

    # 服务列表相关操作
    def init_tv_monitor_service(self):
        """
        创建模型并关联
        :return:
        """
        # 创建一个数据模型
        self.monitor_tv_service_model = QStandardItemModel(0, 3)
        # 设置数据模型的表头标签
        self.monitor_tv_service_model.setHorizontalHeaderLabels(["序号", "服务", "状态"])
        self.ui.tv_monitor_service.setModel(self.monitor_tv_service_model)
        self.ui.tv_monitor_service.resizeColumnsToContents()  # 调整所有列的宽度以适应内容
        self.ui.tv_monitor_service.resizeRowsToContents()  # 调整所有行的高度以适应内容
        self.ui.tv_monitor_service.showGrid()  # 显示网格线
        self.ui.tv_monitor_service.setSortingEnabled(True)  # 排序
        self.ui.tv_monitor_service.horizontalHeader().setStretchLastSection(True)
        # self.ui.tv_tv_monitor_service.etItemDelegate(CustomDelegate()) # 委托
        self.ui.tv_monitor_service.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 表格填满窗口
        self.ui.tv_monitor_service.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置选择行为为选择整行
        self.ui.tv_monitor_service.setSelectionMode(QAbstractItemView.SingleSelection)  # 设置选择模式为单选
        self.ui.tv_monitor_service.selectionModel().selectionChanged.connect(
            self.handle_service_selection_changed)  # 连接选择变化信号与槽函数

    def set_tv_monitor_service_data(self):
        """
        填充数据
        :return:
        """
        try:
            for index, service in enumerate(self.monitor_services):
                print(service)
                service_status = SystemTools.get_services_statu_str(service)
                self.monitor_tv_service_model.setItem(index, 0, QStandardItem(str(index + 1)))
                self.monitor_tv_service_model.setItem(index, 1, QStandardItem(service))
                self.monitor_tv_service_model.setItem(index, 2, QStandardItem(f"服务运行状态={service_status}"))
            self.ui.tv_monitor_service.resizeColumnsToContents()  # 调整所有列的宽度以适应内容
        except Exception as e:
            IcloudpLog.error(f"tableview填充数据失败: {e}")
            DialogUtils.alert(f"tableview填充数据失败: {e}")

    def reload_services(self):
        """
        刷新服务
        :return:
        """
        self.init_tv_monitor_service()
        self.set_tv_monitor_service_data()

    def handle_service_selection_changed(self, selected):
        """
        行选中事件
        :param selected:
        :return:
        """
        if selected.indexes():
            row = selected.indexes()[0].row()  # 获取选中行的索引
            self.ui.txt_monitor_service_name.setText(self.monitor_tv_service_model.item(row, 1).text())
            self.ui.tb_monitor_service_msg.append(self.monitor_tv_service_model.item(row,
                                                                                     2).text() + "\n-----------------------------------------------------------")

    # zmq 相关 =============================
    def zmq_start_proxy(self):
        GlobalData.ZMQ_XPUB_IP = self.ui.txt_zmq_pub_host.text()
        GlobalData.ZMQ_XPUB_PORT = self.ui.txt_zmq_pub_port.text()
        GlobalData.ZMQ_XSUB_IP = self.ui.txt_zmq_sub_host.text()
        GlobalData.ZMQ_XSUB_PORT = self.ui.txt_zmq_sub_port.text()
        self.zmq_proxy = ZmqXProxy()
        self.zmq_proxy.start()
        self.ui.tb_zmq_content.append("代理服务已启动。。。。。。。。")

    def zmq_stop_proxy(self):
        if self.zmq_proxy:
            self.zmq_proxy.stop()
            self.ui.tb_zmq_content.append("代理服务已停止。。。。。。。。")
        else:
            self.ui.tb_zmq_content.append("代理服务不存在。。。。。。。。")

    def zmq_new_pub(self):
        """
        打开新页面创建发布端
        :return:
        """
        try:
            id = TimeUtils.get_current_millisecond()
            zmq_pub_form = ZmqPubForm(id, self)
            zmq_pub_form.win.show()
            self.win_pubs[id] = zmq_pub_form
        except Exception as e:
            self.ui.tb_zmq_content.append(f"打开窗口错误: {e}")
            IcloudpLog.error(f"打开窗口错误: {e}")

    def zmq_new_sub(self):
        """
        打开新页面 创建订阅端
        :return:
        """
        try:
            id = TimeUtils.get_current_millisecond()
            zmq_sub_form = ZmqSubForm(id, self)
            zmq_sub_form.win.show()
            self.win_subs[id] = zmq_sub_form
        except Exception as e:
            self.ui.tb_zmq_content.append(f"打开窗口错误: {e}")
            IcloudpLog.error(f"打开窗口错误: {e}")

    # ======================常用工具====================================
    # -----------------mail---------------------------------------------------
    def send_mails(self):
        recvs = self.ui.txt_common_mail_recvs.text()
        cc = self.ui.txt_common_mail_copys.text()
        topic = self.ui.txt_common_mail_topic.text()
        attachs = self.ui.txt_common_mail_attach.text()
        content = self.ui.txt_common_mail_content.toPlainText()
        if recvs:
            try:
                SendMail.send_mail_html(recvs=recvs, cc=cc, topic=topic, content=content, attachs=attachs)
                DialogUtils.msg("发送邮件成功")
            except Exception as e:
                DialogUtils.alert(f"发送邮件失败：{e}")
        else:
            DialogUtils.warn("接收人不能为空")

    def select_mail_attach(self):
        value, _ = DialogUtils.get_file()
        self.ui.txt_common_mail_attach.setText(value)

    # ======================服务管理====================================
    def service_check(self, type):
        try:
            status, msg = ServiceManage.check(type)
            if type == "gateway":
                self.ui.lab_service_gateway_check.setText(f"{msg}")
                self.ui.lab_service_gateway_check.setStyleSheet("color: #fff;" if status else "color: red")
            else:
                self.ui.lab_service_web_check.setText(f"{msg}")
                self.ui.lab_service_web_check.setStyleSheet("color: #fff;" if status else "color: red")
        except Exception as e:
            DialogUtils.alert(f"检测程序失败：{e}")

    def service_stop(self, type="gateway"):
        try:
            status, msg = ServiceManage.stop(type)
            if type == "gateway":
                self.ui.lab_service_gateway_stop.setText(f"{msg}")
                self.ui.lab_service_gateway_stop.setStyleSheet("color: #fff;" if status else "color: red")
            else:
                self.ui.lab_service_web_stop.setText(f"{msg}")
                self.ui.lab_service_web_stop.setStyleSheet("color: #fff;" if status else "color: red")
        except Exception as e:
            self.log.error(f"停止服务失败: {e}")
            DialogUtils.alert(f"停止服务失败: {e}")

    def service_backup(self, type="gateway"):
        program_path = ""
        file_path = ""
        backup_path = ""
        if type == "gateway":
            program_path = self.ui.txt_service_gateway_program_path.text()
            file_path = self.ui.txt_service_gateway_file_path.text()
            backup_path = self.ui.txt_service_gateway_back_path.text()
        else:
            program_path = self.ui.txt_service_web_program_path.text()
            file_path = self.ui.txt_service_web_file_path.text()
            backup_path = self.ui.txt_service_web_back_path.text()

        if program_path and backup_path:
            try:
                status, msg = ServiceManage.backup(program_path, backup_path, type)
                if type == "gateway":
                    self.ui.lab_service_gateway_back.setText(f"{msg}")
                    self.ui.lab_service_gateway_back.setStyleSheet("color: #fff;" if status else "color: red")
                else:
                    self.ui.lab_service_web_back.setText(f"{msg}")
                    self.ui.lab_service_web_back.setStyleSheet("color: #fff;" if status else "color: red")
            except Exception as e:
                self.log.error(f"备份程序失败: {e}")
                DialogUtils.alert(f"备份程序失败: {e}")
        else:
            DialogUtils.warn("程序目录或者备份路径不能为空")

    def service_update_file(self, type="gateway"):
        program_path = ""
        file_path = ""
        backup_path = ""
        if type == "gateway":
            program_path = self.ui.txt_service_gateway_program_path.text()
            file_path = self.ui.txt_service_gateway_file_path.text()
            backup_path = self.ui.txt_service_gateway_back_path.text()
        else:
            program_path = self.ui.txt_service_web_program_path.text()
            file_path = self.ui.txt_service_web_file_path.text()
            backup_path = self.ui.txt_service_web_back_path.text()
        if program_path and file_path:
            try:
                status, msg = ServiceManage.update(program_path, file_path, type)
                if type == "gateway":
                    self.ui.lab_service_gateway_update.setText(f"{msg}")
                    self.ui.lab_service_gateway_update.setStyleSheet("color: #fff;" if status else "color: red")
                else:
                    self.ui.lab_service_web_update.setText(f"{msg}")
                    self.ui.lab_service_web_update.setStyleSheet("color: #fff;" if status else "color: red")
            except Exception as e:
                self.log.error(f"更新程序失败: {e}")
                DialogUtils.alert(f"更新程序失败: {e}")
        else:
            DialogUtils.warn("程序目录或者更新目录不能为空")

    def service_start(self, type="gateway"):
        try:
            status, msg = ServiceManage.start(type)
            if type == "gateway":
                self.ui.lab_service_gateway_start.setText(f"{msg}")
                self.ui.lab_service_gateway_start.setStyleSheet("color: #fff;" if status else "color: red")
            else:
                self.ui.lab_service_web_start.setText(f"{msg}")
                self.ui.lab_service_web_start.setStyleSheet("color: #fff;" if status else "color: red")
        except Exception as e:
            self.log.error(f"启动服务失败: {e}")
            DialogUtils.alert(f"启动服务失败: {e}")

    def service_start_all(self, type="gateway"):
        """
        一键更新
        :param type:
        :return:
        """
        self.service_check(type)
        QApplication.processEvents()
        # 睡眠一秒
        time.sleep(0.01)
        self.service_stop(type)
        QApplication.processEvents()
        # 睡眠一秒
        time.sleep(0.01)
        self.service_backup(type)
        QApplication.processEvents()
        # 睡眠一秒
        time.sleep(0.01)
        self.service_update_file(type)
        QApplication.processEvents()
        # 睡眠一秒
        time.sleep(0.01)
        self.service_start(type)



    def service_reset(self, type="gateway"):
        if type == "gateway":
            self.ui.lab_service_gateway_check.setText("无")
            self.ui.lab_service_gateway_check.setStyleSheet("color: #fff;")
            self.ui.lab_service_gateway_stop.setText("无")
            self.ui.lab_service_gateway_stop.setStyleSheet("color: #fff;")
            self.ui.lab_service_gateway_back.setText("无")
            self.ui.lab_service_gateway_back.setStyleSheet("color: #fff;")
            self.ui.lab_service_gateway_update.setText("无")
            self.ui.lab_service_gateway_update.setStyleSheet("color: #fff;")
            self.ui.lab_service_gateway_start.setText("无")
            self.ui.lab_service_gateway_start.setStyleSheet("color: #fff;")
        else:
            self.ui.lab_service_web_check.setText("无")
            self.ui.lab_service_web_check.setStyleSheet("color: #fff;")
            self.ui.lab_service_web_stop.setText("无")
            self.ui.lab_service_web_stop.setStyleSheet("color: #fff;")
            self.ui.lab_service_web_back.setText("无")
            self.ui.lab_service_web_back.setStyleSheet("color: #fff;")
            self.ui.lab_service_web_update.setText("无")
            self.ui.lab_service_web_update.setStyleSheet("color: #fff;")
            self.ui.lab_service_web_start.setText("无")
            self.ui.lab_service_web_start.setStyleSheet("color: #fff;")

    def service_restart_cs(self):
        try:
            program_path = self.ui.txt_service_gateway_program_path.text()
            if not program_path:
                DialogUtils.alert("请先配置程序路径")
                return
            path = FileUtils.join_path(program_path, "SADTS", "晟安立体库消防监控平台.exe")
            status, msg = ServiceManage.clear_and_restart(path)
            DialogUtils.msg(msg)
        except Exception as e:
            self.log.error(f"重启客户端失败: {e}")
            DialogUtils.alert(f"重启客户端失败: {e}")

    def service_select_dir(self, flag=1):
        res = DialogUtils.get_dir()
        if flag == 1:
            self.ui.txt_service_gateway_program_path.setText(res)
        elif flag == 2:
            self.ui.txt_service_gateway_back_path.setText(res)
        elif flag == 3:
            self.ui.txt_service_gateway_file_path.setText(res)
        elif flag == 6:
            self.ui.txt_service_web_program_path.setText(res)
        elif flag == 7:
            self.ui.txt_service_web_back_path.setText(res)
        elif flag == 8:
            self.ui.txt_service_web_file_path.setText(res)

    # ======================db管理====================================
    def get_links(self):
        parm_src = {}
        parm_src["host"] = self.ui.txt_db_src_ip.text()
        parm_src["port"] = self.ui.txt_db_src_port.text()
        parm_src["user"] = self.ui.txt_db_src_name.text()
        parm_src["passwd"] = self.ui.txt_db_src_pwd.text()
        parm_src["db"] = self.ui.txt_db_src_db.text()

        parm_target = {}
        parm_target["host"] = self.ui.txt_db_target_ip.text()
        parm_target["port"] = self.ui.txt_db_target_port.text()
        parm_target["user"] = self.ui.txt_db_target_name.text()
        parm_target["passwd"] = self.ui.txt_db_target_pwd.text()
        parm_target["db"] = self.ui.txt_db_target_db.text()

        param_query = {}
        param_query["name"] = self.ui.txt_db_obj_name.text()

        return {"src": parm_src, "target": parm_target, "query": param_query}

    def db_clear_table(self):
        self.ui.tw_db_data.clearContents()
        self.ui.tw_db_data.setRowCount(0)

    def init_db_table(self, rows, cols):
        # self.ui.tw_db_data = QTableWidget(rows, cols)
        self.ui.tw_db_data.setColumnCount(5)
        self.ui.tw_db_data.setRowCount(0)
        self.ui.tw_db_data.setShowGrid(True)
        self.ui.tw_db_data.setHorizontalHeaderLabels(('名称', '类型', '状态', '描述', '操作'))
        self.ui.tw_db_data.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.ui.tw_db_data.setColumnWidth(0, 280)
        self.ui.tw_db_data.setColumnWidth(1, 100)
        self.ui.tw_db_data.setColumnWidth(2, 100)
        self.ui.tw_db_data.setColumnWidth(4, 180)

    def update_table(self, name, datatype, status, res, type):
        r = self.ui.tw_db_data.rowCount()
        self.ui.tw_db_data.insertRow(r)
        self.ui.tw_db_data.setRowHeight(r, 45)
        item = QTableWidgetItem(name)
        if res:
            item.setForeground(QColor("red"))
        self.ui.tw_db_data.setItem(r, 0, item)

        item = QTableWidgetItem(datatype)
        if res:
            item.setForeground(QColor("red"))
        self.ui.tw_db_data.setItem(r, 1, item)

        item = QTableWidgetItem(status)
        if res:
            item.setForeground(QColor("red"))
        self.ui.tw_db_data.setItem(r, 2, item)

        item = QTableWidgetItem(res)
        if res:
            item.setForeground(QColor("red"))
        self.ui.tw_db_data.setItem(r, 3, item)

        # 创建一个 QWidget 对象
        widget = QWidget()
        # 创建一个布局并添加一个按钮
        layout = QHBoxLayout()
        btn_op = QPushButton("覆盖")
        btn_op.setStyleSheet("QPushButton { width: 95%; height: 99%; }")  # 设置按钮样式
        btn_op.clicked.connect(lambda: self.db_table_op(name, datatype, type))
        layout.addWidget(btn_op)
        if type == 'table1':
            btn_up = QPushButton("更新")
            btn_up.setStyleSheet("QPushButton { width: 45%; height: 99%; }")  # 设置按钮样式
            btn_up.clicked.connect(lambda: self.db_table_up(name, datatype, type))
            layout.addWidget(btn_up)
        widget.setLayout(layout)
        self.ui.tw_db_data.setCellWidget(r, 4, widget)
        # 实时刷新界面
        QApplication.processEvents()
        # 睡眠一秒
        time.sleep(0.01)

    # 测试连接
    def db_link_test(self, type):
        links = self.get_links()
        if type == "src":
            params = links["src"]
        else:
            params = links["target"]
        if params["host"] and params["port"] and params["user"] and params["passwd"] and params["db"]:
            try:
                DbManage.test_link(params)
                DialogUtils.msg("连接成功！！！")
            except Exception as e:
                DialogUtils.alert(f"连接失败！！！{str(e)}")
        else:
            DialogUtils.msg("数据库ip、端口、用户、密码、数据库名不能为空")

    # 触发行按钮事件
    def db_table_op(self, name, datatype, type):
        if not DialogUtils.checkRes(DialogUtils.confirm("是否确认覆盖目标表/过程/用户，将清理所有数据！")):
            return
        links = self.get_links()
        if type == "table":
            try:
                DbManage.create_table(links, name)
                DialogUtils.msg("创建成功，请刷新查看")
            except Exception as e:
                DialogUtils.alert(f"创建表失败！！！{str(e)}")
        elif type == "proc":
            try:
                DbManage.create_proc(links, name, datatype)
                DialogUtils.msg("创建成功，请刷新查看")
            except Exception as e:
                DialogUtils.alert(f"创建存储过程失败！！！{str(e)}")
        elif type == "remote_user":
            try:
                DbManage.add_remote_user(links["target"])
                DialogUtils.msg("创建远程用户，请刷新查看")
            except Exception as e:
                DialogUtils.alert(f"创建远程用户失败！！！{str(e)}")

    def db_table_up(self, name, datatype, type):
        links = self.get_links()
        if type == "table":
            DialogUtils.msg("暂未实现，请手动更新！")
        elif type == "proc":
            DialogUtils.msg("暂未实现，请手动更新！")

    # 比对所有表
    def check_tabs(self):
        try:
            links = self.get_links()
            src_tabs = DbManage.select_all_tabls(links["src"], links["query"])

            self.init_db_table(len(src_tabs), 5)
            self.ui.tw_db_data.clearContents()
            index = 0
            for i, ele in enumerate(src_tabs):
                res = DbManage.comparison_tab(links["src"], links["target"], ele['name'])
                status = "成功"
                if res:
                    index = index + 1
                    status = "失败"
                self.update_table(ele['name'], ele["type"], status, res, 'table')
            if index > 0:
                DialogUtils.alert(f"共比对{len(src_tabs)}张表，其中失败{index}张")
            else:
                DialogUtils.msg(f"共比对{len(src_tabs)}张表，全部成功！")
        except Exception as e:
            DialogUtils.alert(f"比较失败！！！{str(e)}")

        # res = DbManage.check_tabs(links["src"], links["target"])
        # print("比对结果:=" + res)

    # 比对所有过程函数
    def check_proc(self):
        try:
            links = self.get_links()
            target_procs = DbManage.select_all_proc(links["target"])
            if target_procs is None or len(target_procs) == 0:
                DialogUtils.alert(f"比较失败，目标库不存在任何过程！！！")
                return

            src_procs = DbManage.select_all_proc(links["src"])

            self.init_db_table(len(src_procs), 3)
            self.ui.tw_db_data.clearContents()
            index = 0
            for i, ele in enumerate(src_procs):
                res = DbManage.comparison_proc(ele["name"], target_procs)
                status = "成功"
                if res:
                    index = index + 1
                    status = "失败"
                self.update_table(ele['name'], ele["type"], status, res, 'proc')
            if index > 0:
                DialogUtils.alert(f"共比对{len(src_procs)}个过程/函数，其中失败{index}个")
            else:
                DialogUtils.msg(f"共比对{len(src_procs)}个过程/函数，全部成功！")
        except Exception as e:
            DialogUtils.alert(f"比较失败！！！{str(e)}")

    # 数据库其他检测
    def db_other(self):
        try:
            links = self.get_links()
            self.init_db_table(5, 3)
            self.ui.tw_db_data.clearContents()
            status = "失败"
            desc = ""
            res = DbManage.check_remote_user(links["target"])
            status = "成功" if res else "失败"
            desc = "" if res else "用户无法远程操作"
            self.update_table("远程账户", "remote_user", status, desc, 'remote_user')
        except Exception as e:
            DialogUtils.alert(f"检测mysql相关配置失败！！！{str(e)}")

    # =================chart==============================
    # 清理页面
    def chart_clear(self, flag):
        if flag == 1:
            self.ui.lw_chart_files.clear()
        elif flag == 2:
            self.ui.tw_chart_data.clearContents()
            self.ui.tw_chart_data.setRowCount(0)
        elif flag == 3:
            if self.ui.lo_chart_chart.count() > 0:
                self.ui.lo_chart_chart.removeWidget(self.ui.lo_chart_chart.itemAt(0).widget())
        elif flag == 100:
            self.ui.lw_chart_files.clear()
            self.ui.tw_chart_data.clearContents()
            self.ui.tw_chart_data.setRowCount(0)
            if self.ui.lo_chart_chart.count() > 0:
                self.ui.lo_chart_chart.removeWidget(self.ui.lo_chart_chart.itemAt(0).widget())
            self.chart_files_list = []
            self.chart_point_data = []

    # 选择目录
    def chart_csv_path(self):
        res = DialogUtils.get_dir(GlobalData.CHART_CSV_PATH)
        if res:
            self.ui.txt_chart_csv_path.setText(res)

    # 选择文件
    def chart_files(self):
        try:
            self.chart_clear(100)
            msg, self.chart_files_list, begin_time, end_time = ChartManage.load_files()
            if msg:
                DialogUtils.alert(msg)
                return
            self.ui.date_chart_curr.setDate(QDate(begin_time.year, begin_time.month, begin_time.day))
            self.ui.time_chart_begin.setTime(QTime(begin_time.hour, begin_time.minute, begin_time.second))
            self.ui.time_chart_end.setTime(QTime(end_time.hour, end_time.minute, end_time.second).addSecs(60))
            for val in self.chart_files_list:
                self.ui.lw_chart_files.addItem(val["path"])
            # 载入数据
            self.chart_load_data()
        except Exception as e:
            DialogUtils.alert(f"选择文件失败！！！{str(e)}")

    # 载入文件数据
    def chart_load_data(self):
        try:
            self.chart_point_data.clear()
            curr_date = self.ui.date_chart_curr.date().toString("yyyy-MM-dd")
            begin_time = self.ui.time_chart_begin.time().toString("HH:mm:00")
            end_time = self.ui.time_chart_end.time().toString("HH:mm:59")
            self.chart_point_data = ChartManage.load_data_by_file(self.chart_files_list, f"{curr_date} {begin_time}", f"{curr_date} {end_time}")
            # print(self.chart_point_data)
            if len(self.chart_point_data) == 0:
                DialogUtils.msg("没有找到符合条件的数据！")
                return
            DialogUtils.msg("载入数据成功！")
        except Exception as e:
            DialogUtils.alert(f"载入数据错误！！！{str(e)}")

    def chart_datetime_select(self, type):
        date_time_edit = DateTimeEdit(type = type)
        res = date_time_edit.exec()
        res_data = date_time_edit.get_data()
        if res == 1:
            if type == "date":
                self.ui.date_chart_curr.setDate(QDate.fromString(res_data["mydate"], "yyyy-MM-dd"))
            elif type == "time_range":
                self.ui.time_chart_begin.setTime(QTime(res_data['start_hour'], res_data['start_minute'], 0))  
                self.ui.time_chart_end.setTime(QTime(res_data['end_hour'], res_data['end_minute'], 0))  
        del date_time_edit




    # 文件点击事件处理
    def chart_file_event(self, dataitem):
        index = self.ui.lw_chart_files.currentIndex().row()
        if len(self.chart_point_data) == 0:
            DialogUtils.warn("未查询到数据。。。")
            return
        self.chart_clear(2)
        self.bind_data(self.chart_point_data[index])

    # 绑定df到表格
    def bind_data(self, df):
        self.ui.tw_chart_data.clearContents()
        self.ui.tw_chart_data.setRowCount(0)
        for num, row in df.iterrows():
            r = self.ui.tw_chart_data.rowCount()
            self.ui.tw_chart_data.insertRow(r)
            item = QTableWidgetItem(row["货位"])
            self.ui.tw_chart_data.setItem(r, 0, item)
            item = QTableWidgetItem(str(row["温度"]))
            self.ui.tw_chart_data.setItem(r, 1, item)

    # 查询货位
    def chart_query(self):
        index = self.ui.lw_chart_files.currentIndex().row()
        if len(self.chart_point_data) == 0:
            DialogUtils.warn("请先载入数据。。。")
            return
        key = self.ui.txt_chart_point.text()
        if key:
            df = self.chart_point_data[index]
            df_new = df[df['货位'].str.contains(key, regex=False)]
            self.bind_data(df_new)

    # 行点击事件
    def chart_tw_rowclick_event(self):
        csvtype = GlobalData.CHART_CSV_TYPE
        row = self.ui.tw_chart_data.currentRow()
        point = self.ui.tw_chart_data.item(row, 0).text()
        self.ui.lab_chart_point.setText(f"当前选中货位：{point}")
        datas = []
        index = 0
        # 获取货位数据
        for df in self.chart_point_data:
            for num, row in df.iterrows():
                if row["货位"] == point:
                    if csvtype == "1":
                        datas.append({"y": row["温度"], "x": self.chart_files_list[index]["time"],
                                  "time": self.chart_files_list[index]["currtime"]})
                    else:
                        datas.append({"y": row["温度"], "x": row["时间"], "time": row["时间"]})
                    break
            index = index + 1
        self.chart_show(datas)

    # 显示趋势图
    def chart_show(self, datas):
        try:
            self.chart_clear(3)
            # 创建图表
            chart = QChart()
            chart.legend().hide()
            # chart.createDefaultAxes()
            chart.setTitle('温度曲线')
            # 设置折线数据
            # line_series = QSplineSeries()
            line_series = QLineSeries()
            min_val = 50
            max_val = 0
            for item in datas:
                line_series.append((QDateTime(item["time"])).toMSecsSinceEpoch(), float(item["y"]))
                temp = int(item["y"])
                if min_val > temp:
                    min_val = temp
                if max_val < temp:
                    max_val = temp
            line_series.setName("温度")
            # 把曲线添加到QChart的实例中
            chart.addSeries(line_series)
            # 声明并初始化X轴，Y轴
            dtaxisX = QDateTimeAxis()
            vlaxisY = QValueAxis()
            # 设置X轴时间样式
            dtaxisX.setFormat("hh:mm:ss")  # 关注就是几小时内的数据，就留时分好了
            # 设置坐标轴上的格点
            # dtaxisX.setTickCount(15)  # 平均分的刻度分隔
            # vlaxisY.setTickCount(10)
            # 设置范围
            if GlobalData.CHART_Y_IS_FIXED == "0":
                # 相对范围 最大最小增加
                vlaxisY.setRange(min_val + int(GlobalData.CHART_Y_MINVAL), max_val + int(GlobalData.CHART_Y_MAXVAL))
            else:
                # 相对范围 最大最小固定
                vlaxisY.setRange(int(GlobalData.CHART_Y_MINVAL),  int(GlobalData.CHART_Y_MAXVAL))
            # 设置坐标轴名称
            dtaxisX.setTitleText("时间")
            vlaxisY.setTitleText("温度")
            # 设置网格显示，并设为灰色
            vlaxisY.setGridLineVisible(True)
            vlaxisY.setGridLineColor(Qt.gray)
            dtaxisX.setGridLineVisible(True)
            dtaxisX.setGridLineColor(Qt.gray)
            # 把坐标轴添加到chart中
            chart.addAxis(dtaxisX, Qt.AlignBottom)
            chart.addAxis(vlaxisY, Qt.AlignLeft)
            # 把曲线关联到坐标轴
            line_series.attachAxis(dtaxisX)
            line_series.attachAxis(vlaxisY)

            # 图表视图
            chartView = QChartView(chart)
            chartView.setRenderHint(QPainter.Antialiasing)

            self.ui.lo_chart_chart.addWidget(chartView)
        except Exception as e:
            # raise Exception(f"执行失败，e={str(e)}")
            DialogUtils.alert(f"加载chart失败！！！{str(e)}")

    def chart_flush_layer(self):
        msg, dirs = ChartManage.load_layer(self.ui.txt_chart_csv_path.text(), self.ui.date_chart_curr.date().toString("yyyyMMdd"))
        if msg:
            DialogUtils.alert(msg)
            return
        self.chart_layers = dirs
        self.ui.cb_chart_layer.clear()
        self.ui.cb_chart_layer.addItems(dirs)

    def chart_query_files(self):
        try:
            self.chart_clear(100)
            csv_path = self.ui.txt_chart_csv_path.text()

            curr_date = self.ui.date_chart_curr.date().toString("yyyyMMdd")
            layer_name = self.ui.cb_chart_layer.itemText(self.ui.cb_chart_layer.currentIndex())
            begin_time = self.ui.time_chart_begin.time().toString("HHmm")
            end_time = self.ui.time_chart_end.time().toString("HHmm")
            msg, files = ChartManage.get_files_by_times(csv_path, curr_date, layer_name, begin_time, end_time)
            if msg:
                DialogUtils.alert(msg)
                return
            self.chart_files_list = files
            for val in self.chart_files_list:
                self.ui.lw_chart_files.addItem(val["path"])
            # 载入数据
            self.chart_load_data()
        except Exception as e:
            DialogUtils.alert(f"筛选文件失败！！！{str(e)}")


    # ==============通用方法========================
    def get_btn_by_name(self, name, obj=QPushButton):
        return self.win.findChild(obj, name)


if __name__ == '__main__':
    print("Python")


#
# class myform(QMainWindow):
#     def __init__(self):
#         super().__init__()
#         # self.button = QPushButton('Close', self)
#         # self.button.clicked.connect(self.close_window)
#
#     def closeEvent(self, event):
#         print("关闭窗口事件")
#         self.close()


class TableViewButtonDelegate(QItemDelegate):
    def paint(self, painter, option, index):
        try:
            if not self.parent().indexWidget(index):
                button_read = QPushButton(
                    self.tr('读'),
                    self.parent()
                    # clicked=self.parent().cellButtonClicked
                )
                button_write = QPushButton(
                    self.tr('写'),
                    self.parent()
                    # clicked=self.parent().cellButtonClicked
                )
                button_read.index = [index.row(), index.column()]
                button_write.index = [index.row(), index.column()]
                h_box_layout = QHBoxLayout()
                h_box_layout.addWidget(button_read)
                h_box_layout.addWidget(button_write)
                h_box_layout.setContentsMargins(0, 0, 0, 0)
                h_box_layout.setAlignment(Qt.AlignCenter)
                widget = QWidget()
                widget.setLayout(h_box_layout)
                self.parent().setIndexWidget(
                    index,
                    widget
                )
        except Exception as e:
            IcloudpLog.error(f"初始化按钮错误: {e}")
